<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <meta name="theme-color" content="#faf8ef">
    <meta name="description" content="2048游戏 - 滑动合并数字">
    <title>2048游戏</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <link rel="manifest" href="manifest.json">
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color: #faf8ef;
            color: #776e65;
            margin: 0;
            padding: 20px;
            user-select: none;
            -webkit-user-select: none;
            touch-action: manipulation;
        }

        .container {
            max-width: 500px;
            margin: 0 auto;
        }

        .header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 20px;
            flex-wrap: wrap;
        }

        h1 {
            font-size: 2.5rem;
            margin: 0;
            font-weight: bold;
            color: #776e65;
        }

        .scores {
            display: flex;
            gap: 10px;
        }

        .score-box {
            background: #bbada0;
            color: white;
            padding: 10px 15px;
            border-radius: 5px;
            text-align: center;
            min-width: 80px;
        }

        .score-title {
            font-size: 0.8rem;
            text-transform: uppercase;
        }

        .score-value {
            font-size: 1.5rem;
            font-weight: bold;
        }

        .game-intro {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 20px;
        }

        .game-explanation {
            font-size: 1rem;
            line-height: 1.4;
        }

        .restart-btn {
            background: #8f7a66;
            color: white;
            border: none;
            border-radius: 5px;
            padding: 10px 20px;
            font-size: 1rem;
            font-weight: bold;
            cursor: pointer;
            transition: all 0.2s;
        }

        .restart-btn:hover {
            background: #9f8b77;
        }

        .game-container {
            position: relative;
            background: #bbada0;
            border-radius: 6px;
            width: 100%;
            padding-bottom: 100%;
            margin-bottom: 20px;
        }

        .game-message {
            display: none;
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: rgba(238, 228, 218, 0.73);
            z-index: 100;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            border-radius: 6px;
        }

        .game-message.game-won {
            background: rgba(237, 194, 46, 0.5);
        }

        .game-message.game-over {
            background: rgba(238, 228, 218, 0.73);
        }

        .game-message p {
            font-size: 3rem;
            font-weight: bold;
            margin: 0;
            color: #776e65;
            text-align: center;
        }

        .game-message .lower {
            margin-top: 20px;
        }

        .grid-container {
            position: absolute;
            z-index: 1;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            display: grid;
            grid-template-columns: repeat(4, 1fr);
            grid-template-rows: repeat(4, 1fr);
            gap: 15px;
            padding: 15px;
            border-radius: 6px;
        }

        .grid-cell {
            background: rgba(238, 228, 218, 0.35);
            border-radius: 3px;
        }

        .tile-container {
            position: absolute;
            z-index: 2;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            display: grid;
            grid-template-columns: repeat(4, 1fr);
            grid-template-rows: repeat(4, 1fr);
            gap: 15px;
            padding: 15px;
            border-radius: 6px;
        }

        .tile {
            position: relative;
            border-radius: 3px;
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 2.5rem;
            font-weight: bold;
            color: #776e65;
            transition: all 0.1s;
        }

        .tile-2 {
            background: #eee4da;
        }

        .tile-4 {
            background: #ede0c8;
        }

        .tile-8 {
            background: #f2b179;
            color: white;
        }

        .tile-16 {
            background: #f59563;
            color: white;
        }

        .tile-32 {
            background: #f67c5f;
            color: white;
        }

        .tile-64 {
            background: #f65e3b;
            color: white;
        }

        .tile-128 {
            background: #edcf72;
            color: white;
            font-size: 2rem;
        }

        .tile-256 {
            background: #edcc61;
            color: white;
            font-size: 2rem;
        }

        .tile-512 {
            background: #edc850;
            color: white;
            font-size: 2rem;
        }

        .tile-1024 {
            background: #edc53f;
            color: white;
            font-size: 1.5rem;
        }

        .tile-2048 {
            background: #edc22e;
            color: white;
            font-size: 1.5rem;
        }

        .tile-super {
            background: #3c3a32;
            color: white;
            font-size: 1.2rem;
        }

        .how-to-play {
            background: #faf8ef;
            padding: 20px;
            border-radius: 6px;
            margin-top: 20px;
        }

        .how-to-play h3 {
            margin-top: 0;
            color: #776e65;
        }

        .keyboard-controls {
            display: none;
        }

        @media (min-width: 768px) {
            .keyboard-controls {
                display: block;
            }
        }

        /* Animation classes */
        .tile-new {
            animation: appear 0.2s;
        }

        .tile-merged {
            animation: pop 0.2s;
        }

        @keyframes appear {
            0% {
                opacity: 0;
                transform: scale(0);
            }

            100% {
                opacity: 1;
                transform: scale(1);
            }
        }

        @keyframes pop {
            0% {
                transform: scale(0.8);
            }

            50% {
                transform: scale(1.1);
            }

            100% {
                transform: scale(1);
            }
        }

        /* PWA styles */
        .install-btn {
            display: none;
            position: fixed;
            bottom: 20px;
            right: 20px;
            background: #8f7a66;
            color: white;
            border: none;
            border-radius: 50%;
            width: 60px;
            height: 60px;
            font-size: 1.5rem;
            cursor: pointer;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
            z-index: 1000;
        }

        @media (max-width: 768px) {
            .install-btn {
                display: flex;
                justify-content: center;
                align-items: center;
            }
        }
    </style>
</head>

<body>
    <div class="container">
        <div class="header">
            <h1>2048</h1>
            <div class="scores">
                <div class="score-box">
                    <div class="score-title">分数</div>
                    <div class="score-value" id="score">0</div>
                </div>
                <div class="score-box">
                    <div class="score-title">最高分</div>
                    <div class="score-value" id="best-score">0</div>
                </div>
            </div>
        </div>

        <div class="game-intro">
            <p class="game-explanation">
                使用方向键或滑动屏幕移动方块。当两个相同数字的方块相撞时，它们会合并成一个！
            </p>
            <button class="restart-btn" id="restart-btn">新游戏</button>
        </div>

        <div class="game-container">
            <div class="grid-container">
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
            </div>

            <div class="tile-container" id="tile-container"></div>

            <div class="game-message" id="game-message">
                <p id="game-message-text"></p>
                <div class="lower">
                    <button class="restart-btn" id="keep-playing-btn">继续游戏</button>
                    <button class="restart-btn" id="try-again-btn">再试一次</button>
                </div>
            </div>
        </div>

        <div class="how-to-play">
            <h3>游戏规则</h3>
            <p>使用<b>方向键</b>或<b>滑动屏幕</b>移动方块。当两个相同数字的方块相撞时，它们会合并成一个更大的数字！每次移动后，会在空白处随机出现一个2或4的方块。当得到2048方块时，你赢了！当无法移动时，游戏结束。
            </p>

            <div class="keyboard-controls">
                <h3>键盘控制</h3>
                <p>使用键盘方向键(↑, ↓, ←, →)或WASD键控制方块移动。</p>
            </div>
        </div>
    </div>

    <button class="install-btn" id="install-btn" title="安装应用">+</button>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <noscript>
        <style>
            body {
                display: none !important;
            }
        </style>
        <meta http-equiv="refresh" content="0; url=about:blank">
    </noscript>
    <script src="security.js"></script>
    <script>
        $(document).ready(function () {
            // 游戏状态
            let grid = [];
            let score = 0;
            let bestScore = localStorage.getItem('bestScore') || 0;
            let gameOver = false;
            let won = false;
            let keepPlaying = false;
            let touchStartX = 0;
            let touchStartY = 0;
            let touchEndX = 0;
            let touchEndY = 0;

            // DOM元素
            const tileContainer = $('#tile-container');
            const scoreElement = $('#score');
            const bestScoreElement = $('#best-score');
            const gameMessage = $('#game-message');
            const gameMessageText = $('#game-message-text');
            const restartBtn = $('#restart-btn');
            const keepPlayingBtn = $('#keep-playing-btn');
            const tryAgainBtn = $('#try-again-btn');
            const installBtn = $('#install-btn');

            // 初始化游戏
            function initGame() {
                grid = [
                    [0, 0, 0, 0],
                    [0, 0, 0, 0],
                    [0, 0, 0, 0],
                    [0, 0, 0, 0]
                ];

                score = 0;
                gameOver = false;
                won = false;
                keepPlaying = false;

                scoreElement.text(score);
                bestScoreElement.text(bestScore);

                tileContainer.empty();
                gameMessage.hide().removeClass('game-won game-over');

                // 添加两个初始方块
                addRandomTile();
                addRandomTile();

                updateView();
            }

            // 添加随机方块
            function addRandomTile() {
                if (!hasAvailableCells()) return;

                let value = Math.random() < 0.9 ? 2 : 4;
                let cell = getRandomAvailableCell();

                if (cell) {
                    grid[cell.x][cell.y] = value;
                }
            }

            // 获取随机空白单元格
            function getRandomAvailableCell() {
                let cells = [];

                for (let x = 0; x < 4; x++) {
                    for (let y = 0; y < 4; y++) {
                        if (grid[x][y] === 0) {
                            cells.push({ x: x, y: y });
                        }
                    }
                }

                if (cells.length > 0) {
                    return cells[Math.floor(Math.random() * cells.length)];
                }

                return null;
            }

            // 检查是否有空白单元格
            function hasAvailableCells() {
                for (let x = 0; x < 4; x++) {
                    for (let y = 0; y < 4; y++) {
                        if (grid[x][y] === 0) {
                            return true;
                        }
                    }
                }

                return false;
            }

            // 检查是否可以移动
            function canMove() {
                if (hasAvailableCells()) return true;

                // 检查水平方向是否有可合并的方块
                for (let x = 0; x < 4; x++) {
                    for (let y = 0; y < 3; y++) {
                        if (grid[x][y] === grid[x][y + 1]) {
                            return true;
                        }
                    }
                }

                // 检查垂直方向是否有可合并的方块
                for (let y = 0; y < 4; y++) {
                    for (let x = 0; x < 3; x++) {
                        if (grid[x][y] === grid[x + 1][y]) {
                            return true;
                        }
                    }
                }

                return false;
            }

            // 移动方块
            function move(direction) {
                if (gameOver) return false;

                let moved = false;
                let newGrid = JSON.parse(JSON.stringify(grid));

                // 向左移动
                if (direction === 'left') {
                    for (let x = 0; x < 4; x++) {
                        let row = grid[x].filter(val => val !== 0);
                        let newRow = [];

                        for (let y = 0; y < row.length; y++) {
                            if (y < row.length - 1 && row[y] === row[y + 1]) {
                                newRow.push(row[y] * 2);
                                score += row[y] * 2;
                                y++;
                                moved = true;
                            } else {
                                newRow.push(row[y]);
                            }
                        }

                        while (newRow.length < 4) {
                            newRow.push(0);
                        }

                        newGrid[x] = newRow;
                    }
                }
                // 向右移动
                else if (direction === 'right') {
                    for (let x = 0; x < 4; x++) {
                        let row = grid[x].filter(val => val !== 0);
                        let newRow = [];

                        for (let y = row.length - 1; y >= 0; y--) {
                            if (y > 0 && row[y] === row[y - 1]) {
                                newRow.unshift(row[y] * 2);
                                score += row[y] * 2;
                                y--;
                                moved = true;
                            } else {
                                newRow.unshift(row[y]);
                            }
                        }

                        while (newRow.length < 4) {
                            newRow.unshift(0);
                        }

                        newGrid[x] = newRow;
                    }
                }
                // 向上移动
                else if (direction === 'up') {
                    for (let y = 0; y < 4; y++) {
                        let column = [];

                        for (let x = 0; x < 4; x++) {
                            if (grid[x][y] !== 0) {
                                column.push(grid[x][y]);
                            }
                        }

                        let newColumn = [];

                        for (let x = 0; x < column.length; x++) {
                            if (x < column.length - 1 && column[x] === column[x + 1]) {
                                newColumn.push(column[x] * 2);
                                score += column[x] * 2;
                                x++;
                                moved = true;
                            } else {
                                newColumn.push(column[x]);
                            }
                        }

                        while (newColumn.length < 4) {
                            newColumn.push(0);
                        }

                        for (let x = 0; x < 4; x++) {
                            newGrid[x][y] = newColumn[x];
                        }
                    }
                }
                // 向下移动
                else if (direction === 'down') {
                    for (let y = 0; y < 4; y++) {
                        let column = [];

                        for (let x = 0; x < 4; x++) {
                            if (grid[x][y] !== 0) {
                                column.push(grid[x][y]);
                            }
                        }

                        let newColumn = [];

                        for (let x = column.length - 1; x >= 0; x--) {
                            if (x > 0 && column[x] === column[x - 1]) {
                                newColumn.unshift(column[x] * 2);
                                score += column[x] * 2;
                                x--;
                                moved = true;
                            } else {
                                newColumn.unshift(column[x]);
                            }
                        }

                        while (newColumn.length < 4) {
                            newColumn.unshift(0);
                        }

                        for (let x = 0; x < 4; x++) {
                            newGrid[x][y] = newColumn[x];
                        }
                    }
                }

                if (moved) {
                    grid = newGrid;

                    // 更新分数
                    scoreElement.text(score);
                    if (score > bestScore) {
                        bestScore = score;
                        bestScoreElement.text(bestScore);
                        localStorage.setItem('bestScore', bestScore);
                    }

                    // 添加新方块
                    addRandomTile();

                    // 检查游戏状态
                    if (!won && has2048()) {
                        won = true;
                        showMessage('你赢了!', true);
                    }

                    if (!canMove()) {
                        gameOver = true;
                        showMessage('游戏结束!', false);
                    }

                    updateView();
                }

                return moved;
            }

            // 检查是否有2048方块
            function has2048() {
                for (let x = 0; x < 4; x++) {
                    for (let y = 0; y < 4; y++) {
                        if (grid[x][y] === 2048) {
                            return true;
                        }
                    }
                }

                return false;
            }

            // 显示游戏消息
            function showMessage(message, isWin) {
                gameMessageText.text(message);
                gameMessage.addClass(isWin ? 'game-won' : 'game-over');

                if (isWin) {
                    $('#keep-playing-btn').show();
                } else {
                    $('#keep-playing-btn').hide();
                }

                gameMessage.show();
            }

            // 继续游戏
            function continueGame() {
                keepPlaying = true;
                gameMessage.hide();
            }

            // 更新视图
            function updateView() {
                tileContainer.empty();

                for (let x = 0; x < 4; x++) {
                    for (let y = 0; y < 4; y++) {
                        if (grid[x][y] !== 0) {
                            let value = grid[x][y];
                            let tile = $('<div>').addClass('tile tile-' + value);

                            if (value > 2048) {
                                tile.addClass('tile-super');
                            }

                            tile.text(value);
                            tile.css({
                                'grid-column': y + 1,
                                'grid-row': x + 1
                            });

                            tileContainer.append(tile);
                        }
                    }
                }
            }

            // 键盘事件
            $(document).keydown(function (e) {
                let moved = false;

                switch (e.key) {
                    case 'ArrowLeft':
                    case 'a':
                    case 'A':
                        moved = move('left');
                        break;
                    case 'ArrowRight':
                    case 'd':
                    case 'D':
                        moved = move('right');
                        break;
                    case 'ArrowUp':
                    case 'w':
                    case 'W':
                        moved = move('up');
                        break;
                    case 'ArrowDown':
                    case 's':
                    case 'S':
                        moved = move('down');
                        break;
                }

                if (moved) {
                    e.preventDefault();
                }
            });

            // 触摸事件
            tileContainer.on('touchstart', function (e) {
                touchStartX = e.originalEvent.touches[0].clientX;
                touchStartY = e.originalEvent.touches[0].clientY;
            });

            tileContainer.on('touchmove', function (e) {
                e.preventDefault();
            });

            tileContainer.on('touchend', function (e) {
                touchEndX = e.originalEvent.changedTouches[0].clientX;
                touchEndY = e.originalEvent.changedTouches[0].clientY;

                handleSwipe();
            });

            // 处理滑动
            function handleSwipe() {
                let dx = touchEndX - touchStartX;
                let dy = touchEndY - touchStartY;
                let absDx = Math.abs(dx);
                let absDy = Math.abs(dy);

                if (Math.max(absDx, absDy) > 30) { // 最小滑动距离
                    if (absDx > absDy) {
                        if (dx > 0) {
                            move('right');
                        } else {
                            move('left');
                        }
                    } else {
                        if (dy > 0) {
                            move('down');
                        } else {
                            move('up');
                        }
                    }
                }
            }

            // 按钮事件
            restartBtn.click(initGame);
            keepPlayingBtn.click(continueGame);
            tryAgainBtn.click(initGame);

            // PWA安装提示
            let deferredPrompt;

            window.addEventListener('beforeinstallprompt', (e) => {
                e.preventDefault();
                deferredPrompt = e;
                installBtn.show();
            });

            installBtn.click(async () => {
                if (deferredPrompt) {
                    deferredPrompt.prompt();
                    const { outcome } = await deferredPrompt.userChoice;
                    if (outcome === 'accepted') {
                        installBtn.hide();
                    }
                    deferredPrompt = null;
                }
            });

            // 初始化游戏
            initGame();
        });
    </script>

    <script>
        // Service Worker注册
        if ('serviceWorker' in navigator) {
            window.addEventListener('load', () => {
                navigator.serviceWorker.register('sw.js').then(registration => {
                    console.log('ServiceWorker注册成功:', registration.scope);
                }).catch(error => {
                    console.log('ServiceWorker注册失败:', error);
                });
            });
        }
    </script>
</body>

</html>